/* Copyright (C) 2011 The University of Michigan This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. Please send inquiries to powertutor@umich.edu */ package vn.cybersoft.obs.andriod.batterystats2.components; import vn.cybersoft.obs.andriod.batterystats2.service.IterationData; import android.os.SystemClock; import android.util.Log; public abstract class PowerComponent extends Thread { private final String TAG = "PowerComponent"; /* * Extending classes need to override the calculateIteration function. It * should calculate the data point for the given component in a timely * manner (under 1 second, longer times will cause data to be missed). The * iteration parameter can be ignored in most cases. */ protected abstract IterationData calculateIteration(long iteration); /* * Extending classes should provide a recognizable name for this component * to be used when writing to logs. */ public abstract String getComponentName(); /* * Returns true if this component collects usage information per uid. */ public boolean hasUidInformation() { return false; } /* * Called when the thread running this interface is asked to exit. */ protected void onExit() { } /* * In general we should only need to buffer two data elements. */ private IterationData data1; private IterationData data2; private long iteration1; private long iteration2; protected long beginTime; protected long iterationInterval; public PowerComponent() { setDaemon(true); } /* * This is called once at the begginning of the daemon loop. */ public void init(long beginTime, long iterationInterval) { this.beginTime = beginTime; this.iterationInterval = iterationInterval; data1 = data2 = null; iteration1 = iteration2 = -1; } /* Runs the daemon loop that collects data for this component. */ public void run() { android.os.Process .setThreadPriority(android.os.Process.THREAD_PRIORITY_MORE_FAVORABLE); for (long iter = 0; !Thread.interrupted();) { /* * Hand off to the client class to actually calculate the * information we want for this component. */ IterationData data = calculateIteration(iter); if (data != null) { synchronized (this) { if (iteration1 < iteration2) { iteration1 = iter; data1 = data; } else { iteration2 = iter; data2 = data; } } } if (interrupted()) { break; } long curTime = SystemClock.elapsedRealtime(); /* Compute the next iteration that we can make the start of. */ long oldIter = iter; iter = (long) Math.max(iter + 1, 1 + (curTime - beginTime) / iterationInterval); if (oldIter + 1 != iter) { Log.w(TAG, "[" + getComponentName() + "] Had to skip from iteration " + oldIter + " to " + iter); } /* Sleep until the next iteration completes. */ try { sleep(beginTime + iter * iterationInterval - curTime); } catch (InterruptedException e) { break; } } onExit(); } /* * Returns the data point for the given iteration. This method will be * called with a strictly increasing iteration parameter. */ public IterationData getData(long iteration) { synchronized (this) { IterationData ret = null; if (iteration == iteration1) ret = data1; if (iteration == iteration2) ret = data2; if (iteration1 <= iteration) { data1 = null; iteration1 = -1; } if (iteration2 <= iteration) { data2 = null; iteration2 = -1; } if (ret == null) { Log.w(TAG, "[" + getComponentName() + "] Could not find data for " + "requested iteration"); } return ret; } } }